// *********************************************************
//      Copyright (c) Kosta Gaitanis
//      All rights reserved
//
//      k.gaitanis@gmail.com
//
// *********************************************************

#include <QApplication>
#include <QtTest/QtTest>
#include <QDebug>

#include "Tests/TestVector.h"
#include "Tests/TestMatrix.h"
#include "Tests/TestCamera.h"

#include "Matrix.h"
#include "Items/Planet.h"
#include "Items/Rectangle.h"
#include "Items/Car.h"
#include "Items/Sphere.h"
#include "Items/Cylinder.h"

#include "GUI/MainWindow.h"

void createPlanets(MainWindow& w) {
    Texture* texStars = new Texture("Stars", QImage(":/textures/stars"));
    Texture* texMercury = new Texture("Mercury", QImage(":/textures/mercury"));
    Texture* texVenus = new Texture("Venus", QImage(":/textures/venus"));
    Texture* texEarth = new Texture("Earth", QImage(":/textures/earth"));
    Texture* texMoon = new Texture("Moon", QImage(":/textures/moon"));
    Texture* texMars = new Texture("Mars", QImage(":/textures/mars"));
    Texture* texJupiter = new Texture("Jupiter", QImage(":/textures/jupiter"));
    Texture* texSaturn = new Texture("Saturn", QImage(":/textures/saturn"));
    Texture* texNeptune = new Texture("Neptune", QImage(":/textures/neptune"));
    Texture* texPluto = new Texture("Pluto", QImage(":/textures/pluto"));
    Texture* texUranus = new Texture("Uranus", QImage(":/textures/uranus"));
    Texture* texSun = new Texture("Sun", QImage(":/textures/sun"));
    Texture* texIo = new Texture("Io", QImage(":/textures/io"));
    Texture* texCallisto = new Texture("Callisto", QImage(":/textures/callisto"));
    Texture* texEuropa = new Texture("Europa", QImage(":/textures/europa"));
    Texture* texGanymede = new Texture("Ganymede", QImage(":/textures/ganymede"));

    Planet *mercury = new Planet(Planet::Mercury);
    Planet *venus = new Planet(Planet::Venus);
    Planet *earth = new Planet(Planet::Earth);
    Planet *mars = new Planet(Planet::Mars);
    Planet *jupiter = new Planet(Planet::Jupiter);
    Planet *saturn = new Planet(Planet::Saturn);
    Planet *neptune = new Planet(Planet::Neptune);
    Planet *uranus = new Planet(Planet::Uranus);
    Planet *pluto = new Planet(Planet::Pluto);
    Planet *moon = new Planet(Planet::Moon);
    Planet *sun = new Planet(Planet::Sun);

    Sphere *stars = new Sphere(4000, 1, "Stars");
    stars->getMaterial()->setEmission(QColor(200,200,255));

    Planet *io = new Planet(Planet::Io);
    Planet *europa = new Planet(Planet::Europa);
    Planet *ganymede = new Planet(Planet::Ganimede);
    Planet *callisto = new Planet(Planet::Callisto);

    earth->addSatelite(moon);
    jupiter->addSatelite(io);
    jupiter->addSatelite(europa);
    jupiter->addSatelite(ganymede);
    jupiter->addSatelite(callisto);

    sun->addSatelite(mercury);
    sun->addSatelite(venus);
    sun->addSatelite(earth);
    sun->addSatelite(mars);
    sun->addSatelite(jupiter);
    sun->addSatelite(saturn);
    sun->addSatelite(neptune);
    sun->addSatelite(uranus);
    sun->addSatelite(pluto);

    w.addItem(stars);
    w.addItem(sun);

    w.bindTexture(texMercury, mercury);
    w.bindTexture(texVenus, venus);
    w.bindTexture(texEarth, earth);
    w.bindTexture(texMoon, moon);
    w.bindTexture(texMars, mars);
    w.bindTexture(texJupiter, jupiter);
    w.bindTexture(texSaturn, saturn);
    w.bindTexture(texNeptune, neptune);
    w.bindTexture(texPluto, pluto);
    w.bindTexture(texUranus, uranus);
    w.bindTexture(texSun, sun);
    w.bindTexture(texIo, io);
    w.bindTexture(texCallisto, callisto);
    w.bindTexture(texEuropa, europa);
    w.bindTexture(texGanymede, ganymede);
    w.bindTexture(texStars, stars);

    w.addLight(new Light());
    w.setCameraTarget(earth);
    w.getCamera()->setFarLimit(10000);
}

void createRectangle(MainWindow& w) {
    Rectangle *cube = new Rectangle(0.5, 1, 2);
    cube->getMaterial()->setDiffuse(Qt::blue);
    w.addItem(cube);

    Light* light = new Light();
    light->setPosition(-2,1,1);
    w.addLight(light);

    Texture* texMercury = new Texture("Mercury", QImage(":/textures/mercury"));
    w.bindTexture(texMercury, cube);
}

void createSphere(MainWindow& w, int radius = 400) {
    Sphere *sphere = new Sphere(radius);
    sphere->getMaterial()->setDiffuse(Qt::blue);
    sphere->getMaterial()->setSpecular(Qt::white);
    sphere->getMaterial()->setAmbient(Qt::white);
    w.addItem(sphere);

    Light* light = new Light();    
    light->setPosition(-2,1,1);
    w.addLight(light);
    Texture* texEarth = new Texture("Earth", QImage(":/textures/earth"));
    w.bindTexture(texEarth, sphere);
}

void createCylinder(MainWindow& w) {
    Cylinder *cylinder = new Cylinder(1.0, 2.0);
    cylinder->getMaterial()->setDiffuse(QColor(0,0,255,200));

    w.addItem(cylinder);

    Light* light = new Light();
    light->setPosition(2,0,1);
    w.addLight(light);

}

void createCar(MainWindow& w) {
    Car *car = new Car();
    car->getMaterial()->setDiffuse(Qt::red);
    w.addItem(car);

    Light* light = new Light();
    light->setPosition(-2,0,0);
    w.addLight(light);
}

bool runTests() {
    QObjectList tests;
    tests << new TestVector()
          << new TestMatrix()
          << new TestCamera();

//    tests << new TestVector()
//          << new TestMatrix()
//          << new TestCamera();

    foreach (QObject* test, tests) {
        // run each test
        int result = QTest::qExec(test);
        if (result != 0) {
            // stop execution if any test fails
            return false;
        }
    }
    // delete the tests
    qDeleteAll(tests);

    return true;
}

int main(int argc, char *argv[])
{
    // Load the application and the main window
    QApplication a(argc, argv);
    MainWindow w;

    // proceed execution only if all tests succeed
    if (!runTests()) {
        return -1;
    }

    // set up the items in the world
    //createRectangle(w);
    //createCar(w);
    //createCylinder(w);
    createPlanets(w);
    //createSphere(w,1);


    // set initial camera position
    w.getCamera()->setCameraPosition(10, 0, 0);
    w.getCamera()->setUpDirection(0, 0, 1);

    // Show the main window
    w.show();

    // begin the Qt event loop
    return a.exec();
}



